/*
 * comp.cpp
 *
 *  Created on: 2010.06.26
 *      Author: Tadas
 */

#include "comp.h"
#include <iostream>

using namespace std;

const double PI = acos(-1.);
const double TOL = 1.e-10;

komp::komp(double rea, double ima) //konstruktorius kai duoti skaiciai
{
	im = ima;
	re = rea;
}
;

komp::komp() //default konstruktorius sukuria tuscia skaiciu
{
	im = 0;
	re = 0;
}

komp::komp(const komp &c){
	im = c.im;
	re = c.re;
}

void komp::out(char *str) //kompleksinio skaiciaus isvedimas
{
	printf("%s:\t", str);

	if (im < 0)
		printf("%5.2f %5.2fi", re, im);
	else
		printf("%5.2f +%5.2fi", re, im);
	printf("\n");
}
;

komp operator +(komp a, komp b) //sumos operatorius
{
	komp c;

	c.im = a.im + b.im;
	c.re = a.re + b.re;

	return c;
}
;

komp operator +(komp a, double b) {
	komp c;
	c.im = a.im;
	c.re = a.re + b;
	return c;
}

komp operator +(double b, komp a) {
	komp c;
	c.im = a.im;
	c.re = a.re + b;
	return c;
}

komp operator -(komp a, komp b) //atimties operatorius
{
	komp c;

	c.im = a.im - b.im;
	c.re = a.re - b.re;

	return c;
}
;

komp operator -(komp a, double b) {
	komp c;
	c.im = a.im;
	c.re = a.re - b;
	return c;
}

komp operator -(double b, komp a) {
	komp c;
	c.im = a.im;
	c.re = a.re - b;
	return c;
}

komp operator *(komp a, komp b) //daugybos operatorius
{
	komp c;

	c.re = (a.re * b.re) - (a.im * b.im);
	c.im = (a.re * b.im) + (a.im * b.re);

	return c;
}

komp operator *(komp a, double b) //daugybos operatorius
{
	komp c;

	c.re = (a.re * b);
	c.im = a.im * b;

	return c;
}

komp operator *(double a, komp b) //daugybos operatorius
{
	komp c;

	c.re = (a * b.re);
	c.im = a * b.im;

	return c;
}

komp operator /(komp a, komp b) //dalybos operatorius
{
	komp c;
	double temp;

	temp = b.re*b.re + b.im*b.im;

	c.re = ((a.re * b.re) + (a.im * b.im)) / temp;
	c.im = ((a.im * b.re) - (a.re * b.im)) / temp;

	return c;
}

komp& komp::operator =(double r){  
	im = 0.0;
	re = r;
	return *this; 
} 

double komp::mod(){
	return sqrt(im*im + re*re);
}

double komp::abs(){
	double tmp =  mod();
	if(tmp < 0){
		tmp *= -1;
	}
	return tmp;
}

void komp::set(double r, double i){
	re = r;
	im = i;
}

void komp::set(komp c){
	re = c.re;
	im = c.im;
}

komp komp::power(komp z2) //z1^z2
{
	//basic idea:  from math, its true that z1^z2 = exp(z2*ln(z1)).  Using this form, the complex^complex can be evaluated.
	double n1,n2;
	double a1,a2,b1,b2;
	double mag2= re*re+im*im;
	komp answer;

	if(mag2<=TOL*TOL)
	{
		cout<<"WARNING in z1.ComplexPower(z2):"<<endl;
		cout<<"The magnitude of z1 is below the tolerance"<<endl;
		cout<<"Line: "<<__LINE__<<endl;
	}

	if(re <=TOL)
	{
		cout<<"WARNING in z1.ComplexPower(z2):"<<endl;
		cout<<"The real part of z1 is below the tolerance and so z1 is almost purely imaginary"<<endl;
		cout<<"There is a risk of atan2() not being well defined"<<endl;
		cout<<"Line: "<<__LINE__<<endl;
	}
		
	a1 = 0.5*log(mag2);
	b1 = atan2(im,re);
	a2 = z2.re;
	b2 = z2.im;
	n1 = a2*a1 - b2*b1;
	n2 = b2*a1 + a2*b1;
	answer.re = exp(n1)*cos(n2);
	answer.im = exp(n1)*sin(n2);
	return (answer);

}

ostream& operator<<(ostream &output, komp c) {
    output << "Val : (r:" <<  c.re << ", i:" << c.im <<")";
    return output;
}

komp komp::sqr()
{
	komp a;
	double r, temp;

	r = sqrt(re*re+im*im);

	if ((r + re)==0)
	{
		printf("Klaida traukiant sakni. r+x = 0\n");
		a.re=a.im=1;
		return a;
	}

	a.re = sqrt((r+re)/2);
	temp = sqrt((r+re)*2);
	a.im = im/temp;

	return a;
}



